home *** CD-ROM | disk | FTP | other *** search
/ Aminet 30 / Aminet 30 (1999)(Schatztruhe)[!][Apr 1999].iso / Aminet / gfx / misc / gnuplot-3.7src.lha / gnuplot-3.7src / gnuplot-3.7.lha / gnuplot-3.7 / datafile.c < prev    next >
C/C++ Source or Header  |  1998-11-03  |  39KB  |  1,416 lines

  1. #ifndef lint
  2. static char *RCSid = "$Id: datafile.c,v 1.42 1998/04/14 00:15:17 drd Exp $";
  3. #endif
  4.  
  5. /* GNUPLOT - datafile.c */
  6.  
  7. /*[
  8.  * Copyright 1986 - 1993, 1998   Thomas Williams, Colin Kelley
  9.  *
  10.  * Permission to use, copy, and distribute this software and its
  11.  * documentation for any purpose with or without fee is hereby granted,
  12.  * provided that the above copyright notice appear in all copies and
  13.  * that both that copyright notice and this permission notice appear
  14.  * in supporting documentation.
  15.  *
  16.  * Permission to modify the software is granted, but not the right to
  17.  * distribute the complete modified source code.  Modifications are to
  18.  * be distributed as patches to the released version.  Permission to
  19.  * distribute binaries produced by compiling modified sources is granted,
  20.  * provided you
  21.  *   1. distribute the corresponding source modifications from the
  22.  *    released version in the form of a patch file along with the binaries,
  23.  *   2. add special version identification to distinguish your version
  24.  *    in addition to the base release version number,
  25.  *   3. provide your name and address as the primary contact for the
  26.  *    support of your modified version, and
  27.  *   4. retain our contact information in regard to use of the base
  28.  *    software.
  29.  * Permission to distribute the released version of the source code along
  30.  * with corresponding source modifications in the form of a patch file is
  31.  * granted with same provisions 2 through 4 for binary distributions.
  32.  *
  33.  * This software is provided "as is" without express or implied warranty
  34.  * to the extent permitted by applicable law.
  35. ]*/
  36.  
  37. /* AUTHOR : David Denholm */
  38.  
  39. /*
  40.  * this file provides the functions to handle data-file reading..
  41.  * takes care of all the pipe / stdin / index / using worries
  42.  */
  43.  
  44. /*{{{  notes */
  45. /* couldn't decide how to implement 'thru' only for 2d and 'index'
  46.  * for only 3d, so I did them for both - I can see a use for
  47.  * index in 2d, especially for fit.
  48.  *
  49.  * I keep thru for backwards compatibility, and extend it to allow
  50.  * more natural plot 'data' thru f(y) - I (personally) prefer
  51.  * my syntax, but then I'm biased...
  52.  *
  53.  * - because I needed it, I have added a range of indexes...
  54.  * (s)plot 'data' [index i[:j]]
  55.  *
  56.  * also every a:b:c:d:e:f  - plot every a'th point from c to e,
  57.  * in every b lines from d to f
  58.  * ie for (line=d; line<=f; line+=b)
  59.  *     for (point=c; point >=e; point+=a)
  60.  *
  61.  *
  62.  * I dont like mixing this with the time series hack... I am
  63.  * very into modular code, so I would prefer to not have to
  64.  * have _anything_ to do with time series... for example,
  65.  * we just look at columns in file, and that is independent
  66.  * of 2d/3d. I really dont want to have to pass a flag to
  67.  * this is plot or splot. 
  68.  *
  69.  * use a global array df_timecol[] - cleared by df_open, then
  70.  * columns needing time set by client.
  71.  *
  72.  * Now that df_2dbinary() and df_3dbinary() are here, I am seriously
  73.  * tempted to move get_data() and get_3ddata() in here too
  74.  *
  75.  * public variables declared in this file.
  76.  *    int df_no_use_specs - number of columns specified with 'using'
  77.  *    int df_line_number  - for error reporting
  78.  *    int df_datum        - increases with each data point
  79.  *    TBOOLEAN df_binary  - it's a binary file
  80.  *        [ might change this to return value from df_open() ]
  81.  *    int df_eof          - end of file
  82.  *    int df_timecol[]    - client controls which cols read as time
  83.  *
  84.  * functions 
  85.  *   int df_open(int max_using)
  86.  *      parses thru / index / using on command line
  87.  *      max_using is max no of 'using' columns allowed
  88.  *      returns number of 'using' cols specified, or -1 on error (?)
  89.  *
  90.  *   int df_readline(double vector[], int max)
  91.  *      reads a line, does all the 'index' and 'using' manipulation
  92.  *      deposits values into vector[]
  93.  *      returns
  94.  *          number of columns parsed  [0=not blank line, but no valid data],
  95.  *          DF_EOF for EOF
  96.  *          DF_UNDEFINED - undefined result during eval of extended using spec
  97.  *          DF_FIRST_BLANK for first consecutive blank line
  98.  *          DF_SECOND_BLANK for second consecutive blank line
  99.  *            will return FIRST before SECOND
  100.  *
  101.  * if a using spec was given, lines not fulfilling spec are ignored.
  102.  * we will always return exactly the number of items specified
  103.  *
  104.  * if no spec given, we return number of consecutive columns we parsed.
  105.  * 
  106.  * if we are processing indexes, seperated by 'n' blank lines,
  107.  * we will return n-1 blank lines before noticing the index change
  108.  *
  109.  *   void df_close()
  110.  *     closes a currently open file.
  111.  *
  112.  *    void f_dollars(x)
  113.  *    void f_column()    actions for expressions using $i, column(j), etc
  114.  *    void f_valid()     
  115.  * 
  116.  *
  117.  * line parsing slightly differently from previous versions of gnuplot...
  118.  * given a line containing fewer columns than asked for, gnuplot used to make
  119.  * up values... I say that if I have explicitly said 'using 1:2:3', then if
  120.  * column 3 doesn't exist, I dont want this point...
  121.  *
  122.  * a column number of 0 means generate a value... as before, this value
  123.  * is useful in 2d as an x value, and is reset at blank lines.
  124.  * a column number of -1 means the (data) line number (not the file line
  125.  * number).  splot 'file' using 1  is equivalent to
  126.  * splot 'file' using 0:-1:1
  127.  * column number -2 is the index. It was put in to kludge multi-branch
  128.  * fitting.
  129.  *
  130.  * 20/5/95 : accept 1.23d4 in place of e (but not in scanf string)
  131.  *         : autoextend data line buffer and MAX_COLS
  132.  *
  133.  * 11/8/96 : add 'columns' -1 for suggested y value, and -2 for
  134.  *           current index.
  135.  *           using 1:-1:-2  and  column(-1)  are supported.
  136.  *           $-1 and $-2 are not yet supported, because of the
  137.  *           way the parser works
  138.  *
  139.  */
  140. /*}}} */
  141.  
  142. #include "plot.h"
  143. #include "fnproto.h"        /* check prototypes against our defns */
  144. #include "binary.h"
  145. #include "setshow.h"
  146.  
  147. /* if you change this, change the scanf in readline */
  148. #define NCOL   7        /* max using specs     */
  149.  
  150. /*{{{  static fns */
  151. #if 0                /* not used */
  152. static int get_time_cols __PROTO((char *fmt));
  153. static void mod_def_usespec __PROTO((int specno, int jump));
  154. #endif
  155. static int check_missing __PROTO((char *s));
  156. static char *df_gets __PROTO((void));
  157. static int df_tokenise __PROTO((char *s));
  158. static float **df_read_matrix __PROTO((int *rows, int *columns));
  159. /*}}} */
  160.  
  161. /*{{{  variables */
  162. struct use_spec_s {
  163.     int column;
  164.     struct at_type *at;
  165. };
  166.  
  167. /* public variables client might access */
  168.  
  169. int df_no_use_specs;        /* how many using columns were specified */
  170. int df_line_number;
  171. int df_datum;            /* suggested x value if none given */
  172. TBOOLEAN df_matrix = FALSE;    /* is this a matrix splot */
  173. int df_eof = 0;
  174. int df_timecol[NCOL];
  175. TBOOLEAN df_binary = FALSE;    /* this is a binary file */
  176.  
  177. /* private variables */
  178.  
  179. /* in order to allow arbitrary data line length, we need to use the heap
  180.  * might consider free-ing it in df_close, especially for small systems
  181.  */
  182. static char *line = NULL;
  183. static int max_line_len = 0;
  184.  
  185. static FILE *data_fp = NULL;
  186. static TBOOLEAN pipe_open = FALSE;
  187. static TBOOLEAN mixed_data_fp = FALSE;
  188.  
  189. #ifndef MAXINT            /* should there be one already defined ? */
  190. # ifdef INT_MAX            /* in limits.h ? */
  191. #  define MAXINT INT_MAX
  192. # else
  193. #  define MAXINT ((~0)>>1)
  194. # endif
  195. #endif
  196.  
  197. /* stuff for implementing index */
  198. static int blank_count = 0;    /* how many blank lines recently */
  199. static int df_lower_index = 0;    /* first mesh required */
  200. static int df_upper_index = MAXINT;
  201. static int df_index_step = 1;    /* 'every' for indices */
  202. static int df_current_index;    /* current mesh */
  203.  
  204. /* stuff for every point:line */
  205. static int everypoint = 1;
  206. static int firstpoint = 0;
  207. static int lastpoint = MAXINT;
  208. static int everyline = 1;
  209. static int firstline = 0;
  210. static int lastline = MAXINT;
  211. static int point_count = -1;    /* point counter - preincrement and test 0 */
  212. static int line_count = 0;    /* line counter */
  213.  
  214. /* parsing stuff */
  215. static struct use_spec_s use_spec[NCOL];
  216. static char df_format[MAX_LINE_LEN + 1];
  217.  
  218. /* rather than three arrays which all grow dynamically, make one
  219.  * dynamic array of this structure
  220.  */
  221.  
  222. typedef struct df_column_struct {
  223.     double datum;
  224.     enum {
  225.     DF_MISSING, DF_BAD, DF_GOOD
  226.     } good;
  227.     char *position;
  228. } df_column_struct;
  229.  
  230. static df_column_struct *df_column = NULL;    /* we'll allocate space as needed */
  231. static int df_max_cols = 0;    /* space allocated */
  232. static int df_no_cols;        /* cols read */
  233. static int fast_columns;    /* corey@cac optimization */
  234.  
  235. /* external variables we need */
  236.  
  237. extern int c_token, num_tokens;
  238. extern char timefmt[];        /* I would rather not need this, but ... */
  239. /* columns needing timefmt are passed in df_timecol[] after df_open */
  240.  
  241. /* jev -- for passing data thru user-defined function */
  242. extern struct udft_entry ydata_func;
  243. extern struct udft_entry *dummy_func;
  244. extern char dummy_var[MAX_NUM_VAR][MAX_ID_LEN + 1];
  245. extern char c_dummy_var[MAX_NUM_VAR][MAX_ID_LEN + 1];
  246.  
  247. extern double min_array[], max_array[];
  248. /*}}} */
  249.  
  250.  
  251. /*{{{  static char *df_gets() */
  252. static char *df_gets()
  253. {
  254.     int len = 0;
  255.  
  256.     if (!fgets(line, max_line_len, data_fp))
  257.     return NULL;
  258.  
  259.     if (mixed_data_fp)
  260.     ++inline_num;
  261.  
  262.     for (;;) {
  263.     len += strlen(line + len);
  264.  
  265.     if (len > 0 && line[len - 1] == '\n') {
  266.         /* we have read an entire text-file line.
  267.          * Strip the trailing linefeed and return
  268.          */
  269.         line[len - 1] = 0;
  270.         return line;
  271.     }
  272.     /* buffer we provided may not be full - dont grab extra
  273.      * memory un-necessarily. This may trap a problem with last
  274.      * line in file not being properly terminated - each time
  275.      * through a replot loop, it was doubling buffer size
  276.      */
  277.  
  278.     if ((max_line_len - len) < 32)
  279.         line = gp_realloc(line, max_line_len *= 2, "datafile line buffer");
  280.  
  281.     if (!fgets(line + len, max_line_len - len, data_fp))
  282.         return line;    /* unexpected end of file, but we have something to do */
  283.     }
  284.  
  285.     /* NOTREACHED */
  286.     return NULL;
  287. }
  288. /*}}} */
  289.  
  290. /*{{{  static int df_tokenise(s) */
  291. static int df_tokenise(s)
  292. char *s;
  293. {
  294.     /* implement our own sscanf that takes 'missing' into account,
  295.      * and can understand fortran quad format
  296.      */
  297.  
  298.     df_no_cols = 0;
  299.  
  300.     while (*s) {
  301.  
  302.     /* check store - double max cols or add 20, whichever is greater */
  303.     if (df_max_cols <= df_no_cols)
  304.         df_column = (df_column_struct *) gp_realloc(df_column, (df_max_cols += (df_max_cols < 20 ? 20 : df_max_cols)) * sizeof(df_column_struct), "datafile column");
  305.  
  306.     /* have always skipped spaces at this point */
  307.     df_column[df_no_cols].position = s;
  308.  
  309.     if (check_missing(s))
  310.         df_column[df_no_cols].good = DF_MISSING;
  311.     else {
  312. #ifdef OSK
  313.         /* apparently %n does not work. This implementation
  314.          * is just as good as the non-OSK one, but close
  315.          * to a release (at last) we make it os-9 specific
  316.          */
  317.         int count;
  318.         char *p = strpbrk(s, "dqDQ");
  319.         if (p != NULL)
  320.         *p = 'e';
  321.  
  322.         count = sscanf(s, "%lf", &df_column[df_no_cols].datum);
  323. #else
  324.         /* cannot trust strtod - eg strtod("-",&p) */
  325.         int used;
  326.         int count;
  327.         int dfncp1 = df_no_cols + 1;
  328.  
  329. /*
  330.  * optimizations by Corey Satten, corey@cac.washington.edu
  331.  */
  332.         if (fast_columns == 0 ||
  333.         df_no_use_specs > 0 && (use_spec[0].column == dfncp1 ||
  334.           df_no_use_specs > 1 && (use_spec[1].column == dfncp1 ||
  335.           df_no_use_specs > 2 && (use_spec[2].column == dfncp1 ||
  336.           df_no_use_specs > 3 && (use_spec[3].column == dfncp1 ||
  337.           df_no_use_specs > 4 && (use_spec[4].column == dfncp1 ||
  338.                       df_no_use_specs > 5))))) ||
  339.         df_no_use_specs == 0) {
  340.  
  341. #ifndef NO_FORTRAN_NUMS
  342.         count = sscanf(s, "%lf%n", &df_column[df_no_cols].datum, &used);
  343. #else
  344.         while (isspace(*s))
  345.             ++s;
  346.         count = *s ? 1 : 0;
  347.         df_column[df_no_cols].datum = atof(s);
  348. #endif /* NO_FORTRAN_NUMS */
  349.         } else {
  350.         /* skip any space at start of column */
  351.         while (isspace((int)*s))
  352.             ++s;
  353.         count = *s ? 1 : 0;
  354.         /* skip chars to end of column */
  355.         for (used = 0; !isspace((int)*s) && (*s != NUL); ++used, ++s)
  356.             ;
  357.         }
  358.  
  359.         /* it might be a fortran double or quad precision.
  360.          * 'used' is only safe if count is 1
  361.          */
  362.  
  363. #ifndef NO_FORTRAN_NUMS
  364.         if (count == 1 &&
  365.         (s[used] == 'd' || s[used] == 'D' ||
  366.          s[used] == 'q' || s[used] == 'Q')) {
  367.         /* might be fortran double */
  368.         s[used] = 'e';
  369.         /* and try again */
  370.         count = sscanf(s, "%lf", &df_column[df_no_cols].datum);
  371.         }
  372. #endif /* NO_FORTRAN_NUMS */
  373. #endif /* OSK */
  374.         df_column[df_no_cols].good = count == 1 ? DF_GOOD : DF_BAD;
  375.     }
  376.  
  377.     ++df_no_cols;
  378.     /*{{{  skip chars to end of column */
  379.     while ((!isspace((int)*s)) && (*s != '\0'))
  380.         ++s;
  381.     /*}}} */
  382.     /*{{{  skip spaces to start of next column */
  383.     while (isspace((int)*s))
  384.         ++s;
  385.     /*}}} */
  386.     }
  387.  
  388.     return df_no_cols;
  389. }
  390. /*}}} */
  391.  
  392. /*{{{  static float **df_read_matrix() */
  393. /* reads a matrix from a text file
  394.  * stores in same storage format as fread_matrix
  395.  */
  396.  
  397. static float **df_read_matrix(rows, cols)
  398. int *rows, *cols;
  399. {
  400.     int max_rows = 0;
  401.     int c;
  402.     float **rmatrix = NULL;
  403.  
  404.     char *s;
  405.  
  406.     *rows = 0;
  407.     *cols = 0;
  408.  
  409.     for (;;) {
  410.     if (!(s = df_gets())) {
  411.         df_eof = 1;
  412.         return rmatrix;    /* NULL if we have not read anything yet */
  413.     }
  414.     while (isspace((int)*s))
  415.         ++s;
  416.  
  417.     if (!*s || is_comment(*s)) {
  418.         if (rmatrix)
  419.         return rmatrix;
  420.         else
  421.         continue;
  422.     }
  423.     if (mixed_data_fp && is_EOF(*s)) {
  424.         df_eof = 1;
  425.         return rmatrix;
  426.     }
  427.     c = df_tokenise(s);
  428.  
  429.     if (!c)
  430.         return rmatrix;
  431.  
  432.     if (*cols && c != *cols) {
  433.         /* its not regular */
  434.         int_error("Matrix does not represent a grid", NO_CARET);
  435.     }
  436.     *cols = c;
  437.  
  438.     if (*rows >= max_rows) {
  439.         rmatrix = gp_realloc(rmatrix, (max_rows += 10) * sizeof(float *), "df_matrix");
  440.     }
  441.     /* allocate a row and store data */
  442.     {
  443.         int i;
  444.         float *row = rmatrix[*rows] = (float *) gp_alloc(c * sizeof(float), "df_matrix row");
  445.  
  446.         for (i = 0; i < c; ++i) {
  447.         if (df_column[i].good != DF_GOOD)
  448.             int_error("Bad number in matrix", NO_CARET);
  449.  
  450.         row[i] = (float) df_column[i].datum;
  451.         }
  452.  
  453.         ++*rows;
  454.     }
  455.     }
  456. }
  457.  
  458. /*}}} */
  459.  
  460.  
  461. /*{{{  int df_open(max_using) */
  462. int df_open(max_using)
  463. int max_using;
  464.  
  465. /* open file, parsing using/thru/index stuff
  466.  * return number of using specs  [well, we have to return something !]
  467.  */
  468.  
  469. {
  470.     static char filename[MAX_LINE_LEN + 1] = "";
  471.     int i;
  472.     int name_token;
  473.  
  474.     fast_columns = 1;        /* corey@cac */
  475.  
  476.     /*{{{  close file if necessary */
  477.     if (data_fp)
  478.     df_close();
  479.     /*}}} */
  480.  
  481.     /*{{{  initialise static variables */
  482.     df_format[0] = NUL;    /* no format string */
  483.  
  484.     df_no_use_specs = 0;
  485.  
  486.     for (i = 0; i < NCOL; ++i) {
  487.     use_spec[i].column = i + 1;    /* default column */
  488.     use_spec[i].at = NULL;    /* no expression */
  489.     }
  490.  
  491.     if (max_using > NCOL)
  492.     max_using = NCOL;
  493.  
  494.     df_datum = -1;        /* it will be preincremented before use */
  495.     df_line_number = 0;        /* ditto */
  496.  
  497.     df_lower_index = 0;
  498.     df_index_step = 1;
  499.     df_upper_index = MAXINT;
  500.  
  501.     df_current_index = 0;
  502.     blank_count = 2;
  503.     /* by initialising blank_count, leading blanks will be ignored */
  504.  
  505.     everypoint = everyline = 1;    /* unless there is an every spec */
  506.     firstpoint = firstline = 0;
  507.     lastpoint = lastline = MAXINT;
  508.  
  509.     df_eof = 0;
  510.  
  511.     memset(df_timecol, 0, sizeof(df_timecol));
  512.  
  513.     df_binary = 1;
  514.     /*}}} */
  515.  
  516.     assert(max_using <= NCOL);
  517.  
  518.     /* empty name means re-use last one */
  519.  
  520.     {
  521.     char name[MAX_LINE_LEN + 1];
  522.     quote_str(name, c_token, MAX_LINE_LEN);
  523.     if (name[0])
  524.         strcpy(filename, name);
  525.     else if (!filename[0])
  526.         int_error("No previous filename", c_token);
  527.     }
  528.     name_token = c_token++;
  529.  
  530.     /* defer opening until we have parsed the modifiers... */
  531.  
  532.     /*{{{  look for binary / matrix */
  533.     df_binary = df_matrix = FALSE;
  534.  
  535.     if (almost_equals(c_token, "bin$ary")) {
  536.     ++c_token;
  537.     df_binary = TRUE;
  538.     df_matrix = TRUE;
  539.     } else if (almost_equals(c_token, "mat$rix")) {
  540.     ++c_token;
  541.     df_matrix = TRUE;
  542.     }
  543.     /*}}} */
  544.  
  545.     /*{{{  deal with index */
  546.     if (almost_equals(c_token, "i$ndex")) {
  547.     struct value a;
  548.  
  549.     if (df_binary)
  550.         int_error("Binary file format does not allow more than one surface per file", c_token);
  551.  
  552.     ++c_token;
  553.     df_lower_index = (int) real(const_express(&a));
  554.     if (equals(c_token, ":")) {
  555.         ++c_token;
  556.         df_upper_index = (int) magnitude(const_express(&a));
  557.         if (df_upper_index < df_lower_index)
  558.         int_error("Upper index should be bigger than lower index", c_token);
  559.  
  560.         if (equals(c_token, ":")) {
  561.         ++c_token;
  562.         df_index_step = (int) magnitude(const_express(&a));
  563.         if (df_index_step < 1)
  564.             int_error("Index step must be positive", c_token);
  565.         }
  566.     } else
  567.         df_upper_index = df_lower_index;
  568.     }
  569.     /*}}} */
  570.  
  571.     /*{{{  deal with every */
  572.     if (almost_equals(c_token, "ev$ery")) {
  573.     struct value a;
  574.  
  575.     fast_columns = 0;    /* corey@cac */
  576.     /* allow empty fields - every a:b:c::e
  577.      * we have already established the defaults
  578.      */
  579.  
  580.     if (!equals(++c_token, ":")) {
  581.         everypoint = (int) real(const_express(&a));
  582.         if (everypoint < 1)
  583.         int_error("Expected positive integer", c_token);
  584.     }
  585.     /* if it fails on first test, no more tests will succeed. If it
  586.      * fails on second test, next test will succeed with correct c_token
  587.      */
  588.     if (equals(c_token, ":") && !equals(++c_token, ":")) {
  589.         everyline = (int) real(const_express(&a));
  590.         if (everyline < 1)
  591.         int_error("Expected positive integer", c_token);
  592.     }
  593.     if (equals(c_token, ":") && !equals(++c_token, ":")) {
  594.         firstpoint = (int) real(const_express(&a));
  595.         if (firstpoint < 0)
  596.         int_error("Expected non-negative integer", c_token);
  597.     }
  598.     if (equals(c_token, ":") && !equals(++c_token, ":")) {
  599.         firstline = (int) real(const_express(&a));
  600.         if (firstline < 0)
  601.         int_error("Expected non-negative integer", c_token);
  602.     }
  603.     if (equals(c_token, ":") && !equals(++c_token, ":")) {
  604.         lastpoint = (int) real(const_express(&a));
  605.         if (lastpoint < firstpoint)
  606.         int_error("Last point must not be before first point", c_token);
  607.     }
  608.     if (equals(c_token, ":")) {
  609.         ++c_token;
  610.         lastline = (int) real(const_express(&a));
  611.         if (lastline < firstline)
  612.         int_error("Last line must not be before first line", c_token);
  613.     }
  614.     }
  615.     /*}}} */
  616.  
  617.     /*{{{  deal with thru */
  618.     /* jev -- support for passing data from file thru user function */
  619.  
  620.     if (almost_equals(c_token, "thru$")) {
  621.     c_token++;
  622.     if (ydata_func.at)
  623.         free(ydata_func.at);
  624.     strcpy(c_dummy_var[0], dummy_var[0]);
  625.     /* allow y also as a dummy variable.
  626.      * during plot, c_dummy_var[0] and [1] are 'sacred'
  627.      * ie may be set by  splot [u=1:2] [v=1:2], and these
  628.      * names are stored only in c_dummy_var[]
  629.      * so choose dummy var 2 - can anything vital be here ?
  630.      */
  631.     dummy_func = &ydata_func;
  632.     strcpy(c_dummy_var[2], "y");
  633.     ydata_func.at = perm_at();
  634.     dummy_func = NULL;
  635.     } else {
  636.     if (ydata_func.at)
  637.         free(ydata_func.at);
  638.     ydata_func.at = NULL;
  639.     }
  640.     /*}}} */
  641.  
  642.     /*{{{  deal with using */
  643.     if (almost_equals(c_token, "u$sing")) {
  644.     if (!END_OF_COMMAND && !isstring(++c_token)) {
  645.         struct value a;
  646.  
  647.         do {        /* must be at least one */
  648.         if (df_no_use_specs >= max_using)
  649.             int_error("Too many columns in using specification", c_token);
  650.  
  651.         if (equals(c_token, ":")) {
  652.             /* empty specification - use default */
  653.             use_spec[df_no_use_specs].column = df_no_use_specs;
  654.             ++df_no_use_specs;
  655.             /* do not increment c+token ; let while() find the : */
  656.         } else if (equals(c_token, "(")) {
  657.             fast_columns = 0;    /* corey@cac */
  658.             dummy_func = NULL;    /* no dummy variables active */
  659.             use_spec[df_no_use_specs++].at = perm_at();        /* it will match ()'s */
  660.         } else {
  661.             int col = (int) real(const_express(&a));
  662.             if (col < -2)
  663.             int_error("Column must be >= -2", c_token);
  664.             use_spec[df_no_use_specs++].column = col;
  665.         }
  666.         } while (equals(c_token, ":") && ++c_token);
  667.     }
  668.     if (!END_OF_COMMAND && isstring(c_token)) {
  669.         if (df_binary)
  670.         int_error("Format string meaningless with binary data", NO_CARET);
  671.  
  672.         quote_str(df_format, c_token, MAX_LINE_LEN);
  673.         if (!valid_format(df_format))
  674.         int_error("Please use a double conversion %lf", c_token);
  675.  
  676.         c_token++;        /* skip format */
  677.     }
  678.     }
  679.     /*}}} */
  680.  
  681.     /*{{{  more variable inits */
  682.     point_count = -1;        /* we preincrement */
  683.     line_count = 0;
  684.  
  685.     /* here so it's not done for every line in df_readline */
  686.     if (max_line_len < 160)
  687.     line = (char *) gp_alloc(max_line_len = 160, "datafile line buffer");
  688.  
  689.  
  690.     /*}}} */
  691.  
  692.  
  693. /*{{{  open file */
  694. #if defined(PIPES)
  695.     if (*filename == '<') {
  696.     if ((data_fp = popen(filename + 1, "r")) == (FILE *) NULL)
  697.         os_error("cannot create pipe for data", name_token);
  698.     else
  699.         pipe_open = TRUE;
  700.     } else
  701. #endif /* PIPES */
  702.     if (*filename == '-') {
  703.     data_fp = lf_top();
  704.     if (!data_fp)
  705.         data_fp = stdin;
  706.     mixed_data_fp = TRUE;    /* don't close command file */
  707.     } else {
  708.     char msg[MAX_LINE_LEN+1];
  709. #ifdef HAVE_SYS_STAT_H
  710.     struct stat statbuf;
  711.  
  712.     if ((stat(filename, &statbuf) > -1) &&
  713.         !S_ISREG(statbuf.st_mode) && !S_ISFIFO(statbuf.st_mode)) {
  714.         sprintf(msg, "\"%s\" is not a regular file or pipe", filename);
  715.         os_error(msg, name_token);
  716.     }
  717. #endif /* HAVE_SYS_STAT_H */
  718.     if ((data_fp = fopen(filename, df_binary ? "rb" : "r")) == (FILE *) NULL) {
  719.         /* one day we will have proper printf-style error reporting fns */
  720.         sprintf(msg, "can't read data file \"%s\"", filename);
  721.         os_error(msg, name_token);
  722.     }
  723.     }
  724. /*}}} */
  725.  
  726.     return df_no_use_specs;
  727. }
  728. /*}}} */
  729.  
  730. /*{{{  void df_close() */
  731. void df_close()
  732. {
  733.     int i;
  734.     /* paranoid - mark $n and column(n) as invalid */
  735.     df_no_cols = 0;
  736.  
  737.     if (!data_fp)
  738.     return;
  739.  
  740.     if (ydata_func.at) {
  741.     free(ydata_func.at);
  742.     ydata_func.at = NULL;
  743.     }
  744.     /*{{{  free any use expression storage */
  745.     for (i = 0; i < df_no_use_specs; ++i)
  746.     if (use_spec[i].at) {
  747.         free(use_spec[i].at);
  748.         use_spec[i].at = NULL;
  749.     }
  750.     /*}}} */
  751.  
  752.     if (!mixed_data_fp) {
  753. #if defined(PIPES)
  754.     if (pipe_open) {
  755.         (void) pclose(data_fp);
  756.         pipe_open = FALSE;
  757.     } else
  758. #endif /* PIPES */
  759.         (void) fclose(data_fp);
  760.     }
  761.     mixed_data_fp = FALSE;
  762.     data_fp = NULL;
  763. }
  764.  
  765. /*}}} */
  766.  
  767. /*{{{  int df_readline(v, max) */
  768. /* do the hard work... read lines from file,
  769.  * - use blanks to get index number
  770.  * - ignore lines outside range of indices required
  771.  * - fill v[] based on using spec if given
  772.  */
  773.  
  774. int df_readline(v, max)
  775. double v[];
  776. int max;
  777. {
  778.     char *s;
  779.  
  780.     assert(data_fp != NULL);
  781.     assert(!df_binary);
  782.     assert(max_line_len);    /* alloc-ed in df_open() */
  783.     assert(max <= NCOL);
  784.  
  785.     /* catch attempt to read past EOF on mixed-input */
  786.     if (df_eof)
  787.     return DF_EOF;
  788.  
  789.     while ((s = df_gets()) != NULL)
  790.     /*{{{  process line */
  791.     {
  792.     int line_okay = 1;
  793.     int output = 0;        /* how many numbers written to v[] */
  794.  
  795.     ++df_line_number;
  796.     df_no_cols = 0;
  797.  
  798.     /*{{{  check for blank lines, and reject by index/every */
  799.     /*{{{  skip leading spaces */
  800.     while (isspace((int)*s))
  801.         ++s;        /* will skip the \n too, to point at \0  */
  802.     /*}}} */
  803.  
  804.     /*{{{  skip comments */
  805.     if (is_comment(*s))
  806.         continue;        /* ignore comments */
  807.     /*}}} */
  808.  
  809.     /*{{{  check EOF on mixed data */
  810.     if (mixed_data_fp && is_EOF(*s)) {
  811.         df_eof = 1;        /* trap attempts to read past EOF */
  812.         return DF_EOF;
  813.     }
  814.     /*}}} */
  815.  
  816.     /*{{{  its a blank line - update counters and continue or return */
  817.     if (*s == 0) {
  818.         /* argh - this is complicated !  we need to
  819.          *   ignore it if we haven't reached first index
  820.          *   report EOF if passed last index
  821.          *   report blank line unless we've already done 2 blank lines
  822.          *
  823.          * - I have probably missed some obvious way of doing all this,
  824.          * but its getting late
  825.          */
  826.  
  827.         point_count = -1;    /* restart counter within line */
  828.  
  829.         if (++blank_count == 1) {
  830.         /* first blank line */
  831.         ++line_count;
  832.         }
  833.  
  834.         /* just reached end of a group/surface */
  835.         if (blank_count == 2) {
  836.         ++df_current_index;
  837.         line_count = 0;
  838.         df_datum = -1;
  839.         /* ignore line if current_index has just become
  840.          * first required one - client doesn't want this
  841.          * blank line. While we're here, check for <=
  842.          * - we need to do it outside this conditional, but
  843.          * probably no extra cost at assembler level
  844.          */
  845.         if (df_current_index <= df_lower_index)
  846.             continue;    /* dont tell client */
  847.  
  848.         /* df_upper_index is MAXINT-1 if we are not doing index */
  849.         if (df_current_index > df_upper_index) {
  850.             /* oops - need to gobble rest of input if mixed */
  851.             if (mixed_data_fp)
  852.             continue;
  853.             else {
  854.             df_eof = 1;
  855.             return DF_EOF;    /* no point continuing */
  856.             }
  857.         }
  858.         }
  859.         /* dont tell client if we haven't reached first index */
  860.         if (df_current_index < df_lower_index)
  861.         continue;
  862.  
  863.         /* ignore blank lines after blank_index */
  864.         if (blank_count > 2)
  865.         continue;
  866.  
  867.         return DF_FIRST_BLANK - (blank_count - 1);
  868.     }
  869.     /*}}} */
  870.  
  871.     /* get here => was not blank */
  872.  
  873.     blank_count = 0;
  874.  
  875.     /*{{{  ignore points outside range of index */
  876.     /* we try to return end-of-file as soon as we pass upper index,
  877.      * but for mixed input stream, we must skip garbage
  878.      */
  879.  
  880.     if (df_current_index < df_lower_index ||
  881.         df_current_index > df_upper_index ||
  882.         ((df_current_index - df_lower_index) % df_index_step) != 0)
  883.         continue;
  884.     /*}}} */
  885.  
  886.     /*{{{  reject points by every */
  887.     /* accept only lines with (line_count%everyline) == 0 */
  888.  
  889.     if (line_count < firstline || line_count > lastline ||
  890.         (line_count - firstline) % everyline != 0
  891.         )
  892.         continue;
  893.  
  894.     /* update point_count. ignore point if point_count%everypoint != 0 */
  895.  
  896.     if (++point_count < firstpoint || point_count > lastpoint ||
  897.         (point_count - firstpoint) % everypoint != 0
  898.         )
  899.         continue;
  900.     /*}}} */
  901.     /*}}} */
  902.  
  903.     ++df_datum;
  904.  
  905.     /*{{{  do a sscanf */
  906.     if (*df_format)    {
  907.         int i;
  908.  
  909.         assert(NCOL == 7);
  910.  
  911.         /* check we have room for at least 7 columns */
  912.         if (df_max_cols < 7)
  913.         df_column = (df_column_struct *) gp_realloc(df_column, (df_max_cols = 7) * sizeof(df_column_struct), "datafile columns");
  914.  
  915.         df_no_cols = sscanf(line, df_format,
  916.                 &df_column[0].datum,
  917.                 &df_column[1].datum,
  918.                 &df_column[2].datum,
  919.                 &df_column[3].datum,
  920.                 &df_column[4].datum,
  921.                 &df_column[5].datum,
  922.                 &df_column[6].datum);
  923.  
  924.         if (df_no_cols == EOF) {
  925.         df_eof = 1;
  926.         return DF_EOF;    /* tell client */
  927.         }
  928.         for (i = 0; i < df_no_cols; ++i) {    /* may be zero */
  929.         df_column[i].good = DF_GOOD;
  930.         df_column[i].position = NULL;    /* cant get a time */
  931.         }
  932.     }
  933.     /*}}} */
  934.     else
  935.         df_tokenise(s);
  936.  
  937.     /*{{{  copy column[] to v[] via use[] */
  938.     {
  939.         int limit = (df_no_use_specs ? df_no_use_specs : NCOL);
  940.         if (limit > max)
  941.         limit = max;
  942.  
  943.         for (output = 0; output < limit; ++output) {
  944.         /* if there was no using spec, column is output+1 and at=NULL */
  945.         int column = use_spec[output].column;
  946.  
  947.         if (use_spec[output].at) {
  948.             struct value a;
  949.             /* no dummy values to set up prior to... */
  950.             evaluate_at(use_spec[output].at, &a);
  951.             if (undefined)
  952.             return DF_UNDEFINED;    /* store undefined point in plot */
  953.  
  954.             v[output] = real(&a);
  955.         } else if (column == -2) {
  956.             v[output] = df_current_index;
  957.         } else if (column == -1) {
  958.             v[output] = line_count;
  959.         } else if (column == 0) {
  960.             v[output] = df_datum;    /* using 0 */
  961.         } else if (column <= 0)        /* really < -2, but */
  962.             int_error("internal error: column <= 0 in datafile.c", NO_CARET);
  963.         else if (df_timecol[output]) {
  964.             struct tm tm;
  965.             if (column > df_no_cols ||
  966.             df_column[column - 1].good == DF_MISSING ||
  967.             !df_column[column - 1].position ||
  968.             !gstrptime(df_column[column - 1].position, timefmt, &tm)
  969.             ) {
  970.             /* line bad only if user explicitly asked for this column */
  971.             if (df_no_use_specs)
  972.                 line_okay = 0;
  973.  
  974.             /* return or ignore line depending on line_okay */
  975.             break;
  976.             }
  977.             v[output] = (double) gtimegm(&tm);
  978.         } else {    /* column > 0 */
  979.             if ((column <= df_no_cols) && df_column[column - 1].good == DF_GOOD)
  980.             v[output] = df_column[column - 1].datum;
  981.             else {
  982.             /* line bad only if user explicitly asked for this column */
  983.             if (df_no_use_specs)
  984.                 line_okay = 0;
  985.             break;    /* return or ignore depending on line_okay */
  986.             }
  987.         }
  988.         }
  989.     }
  990.     /*}}} */
  991.  
  992.     if (!line_okay)
  993.         continue;
  994.  
  995.     /* output == df_no_use_specs if using was specified
  996.      * - actually, smaller of df_no_use_specs and max
  997.      */
  998.     assert(df_no_use_specs == 0 || output == df_no_use_specs || output == max);
  999.  
  1000.     return output;
  1001.  
  1002.     }
  1003.     /*}}} */
  1004.  
  1005.     /* get here => fgets failed */
  1006.  
  1007.     /* no longer needed - mark column(x) as invalid */
  1008.     df_no_cols = 0;
  1009.  
  1010.     df_eof = 1;
  1011.     return DF_EOF;
  1012. }
  1013. /*}}} */
  1014.  
  1015. /*{{{  int df_2dbinary(this_plot) */
  1016. int df_2dbinary(this_plot)
  1017. struct curve_points *this_plot;
  1018. {
  1019.     int_error("Binary file format for 2d data not yet defined", NO_CARET);
  1020.     return 0;            /* keep compiler happy */
  1021. }
  1022. /*}}} */
  1023.  
  1024. /*{{{  int df_3dmatrix(this_plot, ret_this_iso) */
  1025. /*
  1026.  * formerly in gnubin.c
  1027.  *
  1028.  * modified by div for 3.6
  1029.  *   obey the 'every' field from df_open
  1030.  *   outrange points are marked as such, not omitted
  1031.  *   obey using - treat x as column 1, y as col 2 and z as col 3
  1032.  *   ( ie $1 gets x, $2 gets y, $3 gets z)
  1033.  *
  1034.  *  we are less optimal for case of log plot and no using spec,
  1035.  * (call log too often) but that is price for flexibility
  1036.  * I suspect it didn't do autoscaling of x and y for log scale
  1037.  * properly ?
  1038.  *
  1039.  * Trouble figuring out file format ! Is it
  1040.  
  1041.  width  x1  x2  x3  x4  x5 ...
  1042.  y1   z11 z12 z13 z14 z15 ...
  1043.  y2   x21 z22 z23 .....
  1044.  .    .
  1045.  .        .
  1046.  .             .
  1047.  
  1048.  * with perhaps x and y swapped...
  1049.  *
  1050.  * - presumably rows continue to end of file, hence no indexing...
  1051.  *
  1052.  * Last update: 3/3/92 for Gnuplot 3.24.
  1053.  * Created from code for written by RKC for gnuplot 2.0b.
  1054.  *
  1055.  * 19 September 1992  Lawrence Crowl  (crowl@cs.orst.edu)
  1056.  * Added user-specified bases for log scaling.
  1057.  *
  1058.  * Copyright (c) 1991,1992 Robert K. Cunningham, MIT Lincoln Laboratory
  1059.  *
  1060.  */
  1061.  
  1062. /*
  1063.    Here we keep putting new plots onto the end of the linked list
  1064.  
  1065.    We assume the data's x,y values have x1<x2, x2<x3... and 
  1066.    y1<y2, y2<y3... .
  1067.    Actually, I think the assumption is less strong than that--it looks like
  1068.    the direction just has to be the same.
  1069.    This routine expects the following to be properly initialized:
  1070.    is_log_x, is_log_y, and is_log_z 
  1071.    base_log_x, base_log_y, and base_log_z 
  1072.    log_base_log_x, log_base_log_y, and log_base_log_z 
  1073.    xmin,ymin, and zmin
  1074.    xmax,ymax, and zmax
  1075.    autoscale_lx, autoscale_ly, and autoscale_lz
  1076.  
  1077.    does the autoscaling into the array versions (min_array[], max_array[])
  1078.  */
  1079.  
  1080. int df_3dmatrix(this_plot)
  1081. struct surface_points *this_plot;
  1082. {
  1083.     float GPFAR *GPFAR * dmatrix, GPFAR * rt, GPFAR * ct;
  1084.     int nr, nc;
  1085.     int width, height;
  1086.     int row, col;
  1087.     struct iso_curve *this_iso;
  1088.     double used[3];        /* output from using manip */
  1089.     struct coordinate GPHUGE *point;    /* HBB 980308: added 'GPHUGE' flag */
  1090.  
  1091.     assert(df_matrix);
  1092.  
  1093.     if (df_eof)
  1094.     return 0;        /* hope caller understands this */
  1095.  
  1096.     if (df_binary) {
  1097.     if (!fread_matrix(data_fp, &dmatrix, &nr, &nc, &rt, &ct))
  1098.         int_error("Binary file read error: format unknown!", NO_CARET);
  1099.     /* fread_matrix() drains the file */
  1100.     df_eof = 1;
  1101.     } else {
  1102.     if (!(dmatrix = df_read_matrix(&nr, &nc))) {
  1103.         df_eof = 1;
  1104.         return 0;
  1105.     }
  1106.     rt = NULL;
  1107.     ct = NULL;
  1108.     }
  1109.  
  1110.     if (nc == 0 || nr == 0)
  1111.     int_error("Read grid of zero height or zero width", NO_CARET);
  1112.  
  1113.     this_plot->plot_type = DATA3D;
  1114.     this_plot->has_grid_topology = TRUE;
  1115.  
  1116.     if (df_no_use_specs != 0 && df_no_use_specs != 3)
  1117.     int_error("Current implementation requires full using spec", NO_CARET);
  1118.  
  1119.     if (df_max_cols < 3 &&
  1120.     !(df_column = (df_column_struct *) gp_realloc(df_column, (df_max_cols = 3) * sizeof(df_column_struct), "datafile columns"))
  1121.     )
  1122.     int_error("Out of store in binary read", c_token);
  1123.  
  1124.     df_no_cols = 3;
  1125.     df_column[0].good = df_column[1].good = df_column[2].good = DF_GOOD;
  1126.  
  1127.     assert(everyline > 0);
  1128.     assert(everypoint > 0);
  1129.     width = (nc - firstpoint + everypoint - 1) / everypoint;    /* ? ? ? ? ? */
  1130.     height = (nr - firstline + everyline - 1) / everyline;    /* ? ? ? ? ? */
  1131.  
  1132.     for (row = firstline; row < nr; row += everyline) {
  1133.     df_column[1].datum = rt ? rt[row] : row;
  1134.  
  1135.     /*Allocate the correct number of entries */
  1136.     this_iso = iso_alloc(width);
  1137.  
  1138.     point = this_iso->points;
  1139.  
  1140.     /* Cycle through data */
  1141.     for (col = firstpoint; col < nc; col += everypoint, ++point) {
  1142.         /*{{{  process one point */
  1143.         int i;
  1144.  
  1145.         df_column[0].datum = ct ? ct[col] : col;
  1146.         df_column[2].datum = dmatrix[row][col];
  1147.  
  1148.         /*{{{  pass through using spec */
  1149.         for (i = 0; i < 3; ++i) {
  1150.         int column = use_spec[i].column;
  1151.  
  1152.         if (df_no_use_specs == 0)
  1153.             used[i] = df_column[i].datum;
  1154.         else if (use_spec[i].at) {
  1155.             struct value a;
  1156.             evaluate_at(use_spec[i].at, &a);
  1157.             if (undefined) {
  1158.             point->type = UNDEFINED;
  1159.             goto skip;    /* continue _outer_ loop */
  1160.             }
  1161.             used[i] = real(&a);
  1162.         } else if (column < 1 || column > df_no_cols) {
  1163.             point->type = UNDEFINED;
  1164.             goto skip;
  1165.         } else
  1166.             used[i] = df_column[column - 1].datum;
  1167.         }
  1168.         /*}}} */
  1169.  
  1170.         point->type = INRANGE;    /* so far */
  1171.  
  1172.         /*{{{  autoscaling/clipping */
  1173.         /*{{{  autoscale/range-check x */
  1174.         if (used[0] > 0 || !is_log_x) {
  1175.         if (used[0] < min_array[FIRST_X_AXIS]) {
  1176.             if (autoscale_lx & 1)
  1177.             min_array[FIRST_X_AXIS] = used[0];
  1178.             else
  1179.             point->type = OUTRANGE;
  1180.         }
  1181.         if (used[0] > max_array[FIRST_X_AXIS]) {
  1182.             if (autoscale_lx & 2)
  1183.             max_array[FIRST_X_AXIS] = used[0];
  1184.             else
  1185.             point->type = OUTRANGE;
  1186.         }
  1187.         }
  1188.         /*}}} */
  1189.  
  1190.         /*{{{  autoscale/range-check y */
  1191.         if (used[1] > 0 || !is_log_y) {
  1192.         if (used[1] < min_array[FIRST_Y_AXIS]) {
  1193.             if (autoscale_ly & 1)
  1194.             min_array[FIRST_Y_AXIS] = used[1];
  1195.             else
  1196.             point->type = OUTRANGE;
  1197.         }
  1198.         if (used[1] > max_array[FIRST_Y_AXIS]) {
  1199.             if (autoscale_ly & 2)
  1200.             max_array[FIRST_Y_AXIS] = used[1];
  1201.             else
  1202.             point->type = OUTRANGE;
  1203.         }
  1204.         }
  1205.         /*}}} */
  1206.  
  1207.         /*{{{  autoscale/range-check z */
  1208.         if (used[2] > 0 || !is_log_z) {
  1209.         if (used[2] < min_array[FIRST_Z_AXIS]) {
  1210.             if (autoscale_lz & 1)
  1211.             min_array[FIRST_Z_AXIS] = used[2];
  1212.             else
  1213.             point->type = OUTRANGE;
  1214.         }
  1215.         if (used[2] > max_array[FIRST_Z_AXIS]) {
  1216.             if (autoscale_lz & 2)
  1217.             max_array[FIRST_Z_AXIS] = used[2];
  1218.             else
  1219.             point->type = OUTRANGE;
  1220.         }
  1221.         }
  1222.         /*}}} */
  1223.         /*}}} */
  1224.  
  1225.         /*{{{  log x */
  1226.         if (is_log_x) {
  1227.         if (used[0] < 0.0) {
  1228.             point->type = UNDEFINED;
  1229.             goto skip;
  1230.         } else if (used[0] == 0.0) {
  1231.             point->type = OUTRANGE;
  1232.             used[0] = -VERYLARGE;
  1233.         } else
  1234.             used[0] = log(used[0]) / log_base_log_x;
  1235.         }
  1236.         /*}}} */
  1237.  
  1238.         /*{{{  log y */
  1239.         if (is_log_y) {
  1240.         if (used[1] < 0.0) {
  1241.             point->type = UNDEFINED;
  1242.             goto skip;
  1243.         } else if (used[1] == 0.0) {
  1244.             point->type = OUTRANGE;
  1245.             used[1] = -VERYLARGE;
  1246.         } else
  1247.             used[1] = log(used[1]) / log_base_log_y;
  1248.         }
  1249.         /*}}} */
  1250.  
  1251.         /*{{{  log z */
  1252.         if (is_log_z) {
  1253.         if (used[2] < 0.0) {
  1254.             point->type = UNDEFINED;
  1255.             goto skip;
  1256.         } else if (used[2] == 0.0) {
  1257.             point->type = OUTRANGE;
  1258.             used[2] = -VERYLARGE;
  1259.         } else
  1260.             used[2] = log(used[2]) / log_base_log_z;
  1261.         }
  1262.         /*}}} */
  1263.  
  1264.         point->x = used[0];
  1265.         point->y = used[1];
  1266.         point->z = used[2];
  1267.  
  1268.  
  1269.         /* some of you wont like this, but I say goto is for this */
  1270.  
  1271.       skip:
  1272.         ;            /* ansi requires this */
  1273.         /*}}} */
  1274.     }
  1275.     this_iso->p_count = width;
  1276.     this_iso->next = this_plot->iso_crvs;
  1277.     this_plot->iso_crvs = this_iso;
  1278.     this_plot->num_iso_read++;
  1279.     }
  1280.  
  1281.     free_matrix(dmatrix, 0, nr - 1, 0, nc - 1);
  1282.     if (rt)
  1283.     free_vector(rt, 0, nr - 1);
  1284.     if (ct)
  1285.     free_vector(ct, 0, nc - 1);
  1286.     return (nc);
  1287. }
  1288. /*}}} */
  1289.  
  1290. /* stuff for implementing the call-backs for picking up data values
  1291.  * do it here so we can make the variables private to this file
  1292.  */
  1293.  
  1294. /*{{{  void f_dollars(x) */
  1295. void f_dollars(x)
  1296. union argument *x;
  1297. {
  1298.     int column = x->v_arg.v.int_val - 1;
  1299.     /* we checked it was an integer >= 0 at compile time */
  1300.     struct value a;
  1301.  
  1302.     if (column == -1) {
  1303.     push(Gcomplex(&a, (double) df_datum, 0.0));    /* $0 */
  1304.     } else if (column >= df_no_cols || df_column[column].good != DF_GOOD) {
  1305.     undefined = TRUE;
  1306.     push(&(x->v_arg));    /* this okay ? */
  1307.     } else
  1308.     push(Gcomplex(&a, df_column[column].datum, 0.0));
  1309. }
  1310. /*}}} */
  1311.  
  1312. /*{{{  void f_column() */
  1313. void f_column()
  1314. {
  1315.     struct value a;
  1316.     int column;
  1317.     (void) pop(&a);
  1318.     column = (int) real(&a) - 1;
  1319.     if (column == -2)
  1320.     push(Ginteger(&a, line_count));
  1321.     else if (column == -1)    /* $0 = df_datum */
  1322.     push(Gcomplex(&a, (double) df_datum, 0.0));
  1323.     else if (column < 0 || column >= df_no_cols || df_column[column].good != DF_GOOD) {
  1324.     undefined = TRUE;
  1325.     push(&a);        /* any objection to this ? */
  1326.     } else
  1327.     push(Gcomplex(&a, df_column[column].datum, 0.0));
  1328. }
  1329. /*}}} */
  1330.  
  1331. /*{{{  void f_valid() */
  1332. void f_valid()
  1333. {
  1334.     struct value a;
  1335.     int column, good;
  1336.     (void) pop(&a);
  1337.     column = (int) magnitude(&a) - 1;
  1338.     good = column >= 0 && column < df_no_cols && df_column[column].good == DF_GOOD;
  1339.     push(Ginteger(&a, good));
  1340. }
  1341.  
  1342. /*}}} */
  1343.  
  1344. /*{{{  void f_timecolumn() */
  1345. void f_timecolumn()
  1346. {
  1347.     struct value a;
  1348.     int column;
  1349.     struct tm tm;
  1350.     (void) pop(&a);
  1351.     column = (int) magnitude(&a) - 1;
  1352.     if (column < 0 || column >= df_no_cols ||
  1353.     !df_column[column].position ||
  1354.     !gstrptime(df_column[column].position, timefmt, &tm)
  1355.     ) {
  1356.     undefined = TRUE;
  1357.     push(&a);        /* any objection to this ? */
  1358.     } else
  1359.     push(Gcomplex(&a, gtimegm(&tm), 0.0));
  1360. }
  1361. /*}}} */
  1362.  
  1363. #if 0                /* not used */
  1364. /* count columns in timefmt */
  1365. /*{{{  static int get_time_cols(fmt) */
  1366. static int get_time_cols(fmt)
  1367. char *fmt;            /* format string */
  1368. {
  1369.     int cnt, i;
  1370.     char *p;
  1371.  
  1372.     p = fmt;
  1373.     cnt = 0;
  1374.     while (isspace(*p))
  1375.     p++;
  1376.     if (!strlen(p))
  1377.     int_error("Empty time-data format", NO_CARET);
  1378.     cnt++;
  1379.     for (i = 0; i < strlen(p) - 1; i++) {
  1380.     if (isspace(p[i]) && !isspace(p[i + 1]))
  1381.         cnt++;
  1382.     }
  1383.     return (cnt);
  1384. }
  1385. /*}}} */
  1386.  
  1387. /* modify default use_spec, applies for no user spec and time datacolumns */
  1388. /*{{{  static void mod_def_usespec(specno,jump) */
  1389. static void mod_def_usespec(specno, jump)
  1390. int specno;            /* which spec in ?:?:? */
  1391. int jump;            /* no of columns in timefmt (time data) */
  1392. {
  1393.     int i;
  1394.  
  1395.     for (i = specno + 1; i < NCOL; ++i)
  1396.     use_spec[i].column += jump;    /* add no of columns in time to the rest */
  1397.     df_no_use_specs = 0;
  1398. }
  1399. /*}}} */
  1400. #endif /* not used */
  1401.  
  1402. /*{{{  static int check_missing(s) */
  1403. static int check_missing(s)
  1404. char *s;
  1405. {
  1406.     if (missing_val != NULL) {
  1407.     int len = strlen(missing_val);
  1408.     if (strncmp(s, missing_val, len) == 0 &&
  1409.         (isspace((int)s[len]) || !s[len])) {
  1410.         return (1);;    /* store undefined point in plot */
  1411.     }
  1412.     }
  1413.     return (0);
  1414. }
  1415. /*}}} */
  1416.